﻿#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>
#include <direct.h>
#include <string>
#include <vector>
#include <iostream>

using namespace std;

// dll 名称和游戏名称按需修改
const string strDllName = "wowlua02.dll";
const wstring wstrGameProcessName = L"WowClassic.exe";
// const wstring wstrGameProcessName = L"Wow.exe";

vector<DWORD> pid_vec;

void EnumProcess() {
    PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
    HANDLE processHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    BOOL bRet = Process32First(processHandle, &pe);

    while (bRet) {
        if (!_tcscmp(pe.szExeFile, wstrGameProcessName.c_str())) {
            pid_vec.push_back(pe.th32ProcessID);
            cout << "找到游戏进程, pid = " << pe.th32ProcessID << endl;
        }

        bRet = Process32Next(processHandle, &pe);
    }

    CloseHandle(processHandle);
}

int main() {
    // 1.获取dll全路径
    string strPath;
    char* buff;

    if ((buff = _getcwd(NULL, 0)) == NULL) {
        MessageBoxA(NULL,
            "_getcwd error",
            "error",
            MB_OK);
    } else {
        strPath = buff;
        strPath += "\\";
        strPath += strDllName;
    }

    // 遍历进程获取游戏进程 id
    EnumProcess();

    for (auto iter = pid_vec.begin(); iter != pid_vec.end(); ++iter) {
        // 2.打开进程
        HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS,
            FALSE,
            *iter);

        // 3.申请内存
        LPVOID newAddr = VirtualAllocEx(processHandle,
            0,
            strPath.size(),
            MEM_COMMIT | MEM_RESERVE,
            PAGE_EXECUTE_READWRITE);

        if (!newAddr) {
            MessageBoxA(NULL,
                "申请地址为空",
                "error",
                MB_OK);
            return 0;
        }

        // 4.往申请的内容中写入DLL路径
        SIZE_T size;
        WriteProcessMemory(processHandle,
            newAddr,
            strPath.c_str(),
            strPath.size(),
            &size);

        // 5.远程线程调用
        HANDLE threadHandle = CreateRemoteThread(processHandle,
            NULL,
            NULL,
            (LPTHREAD_START_ROUTINE)LoadLibraryA,
            newAddr,
            NULL,
            NULL);

        // 6.等待
        if (threadHandle) {
            WaitForSingleObject(threadHandle,
                -1);
        }
    }

    return 0;
}